package com.ricky.core.net.protocol;

import java.nio.ByteOrder;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.AttributeKey;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderAdapter;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

import com.ricky.core.net.ByteBuffer;
import com.ricky.core.net.msg.AMF3Context;
import com.ricky.core.net.msg.ByteContext;
import com.ricky.core.net.msg.Context;

public class AMF3STRINGDecoder extends ProtocolDecoderAdapter {

	private final AttributeKey STATE = new AttributeKey(getClass(), "isnew");
	private final AttributeKey BUFFER = new AttributeKey(getClass(), "buffer");
	
	private final class State {
		boolean isnew = true;
		int length = -1;
	}

	
	protected boolean doDecode(IoSession session, IoBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		//log.debug("有数据可以读==================================");
		
		if(session.isClosing()||!session.isConnected()){
			in.position(in.limit());
			return true;
		}	
		
		State state = getState(session);
        Long sendCount = getRecieveCount(session);
		// 新消息
		if (state.isnew) {
			// 小于4字节，连长度都读不出来,只有麻烦mina继续读
			if (in.remaining() < 4){
				//log.debug("小于4个字节");
				return false;
			}	
			int length = in.getInt(in.position());
			if(1819242556 == length){
				in.position(in.position()+1);
//				FlashPolicyMsg fpm = new FlashPolicyMsg();
//				out.write(fpm);
				Context<ByteBuffer> context = new ByteContext(0);
				ByteBuffer buffer=new ByteBuffer();
				buffer.writeUTF(FlashPolicyMsg.allow_all);
				context.setContent(buffer);
				out.write(context);
				//log.debug("flash授权");
				return true;
			}
			
			state.length = length;
			//log.debug("=================="+state.length+"="+in.remaining());
			state.isnew = false;
			if (length + 8 <= in.remaining()) {
				in.getInt();
				int length1 = in.getInt();
                //log.debug(state.length+"---------1收到客户端端消息："+String.format("%1$#9x", type));
				Context<?> msg = new AMF3Context();
				byte[] tmp = new byte[length1];
				in.get(tmp, 0, length);
				msg.decode(tmp);
				out.write(msg);
				state.isnew = true;
				sendCount++;
//				session.setAttribute(Contant.MSG_RECIEVE_COUNT, sendCount);
				return true;
			}else if(length>10485760)//1024*1024*10
			{
				in.position(0);
				
				byte[] decoded = new byte[in.remaining()];
				in.get(decoded);
//				String qqtwg=in.getString(Charset.forName("utf-8").newDecoder());
				String qqtwg=new String(decoded,"utf-8");
				if(qqtwg.indexOf("tgw_l7_forward",0)==-1)
				{
					in.clear();
				}
				
				Context<ByteBuffer> context = new ByteContext(0);
				ByteBuffer buffer=new ByteBuffer();
				buffer.writeUTF(FlashPolicyMsg.allow_all);
				context.setContent(buffer);
				out.write(context);
				state.isnew = true;
				return false;
			}
//			else if(length>512){
//				byte[] tmp = new byte[in.remaining()];
//				in.get(tmp, 0, in.remaining());
//				for(byte b:tmp){
//					//log.debug(b+",");
//				}
//				state.isnew = true;
//				return true;
//			}

		} else if (state.length + 8 <= in.remaining()) {
			int length = in.getInt();// 读取消息内容长度
			byte[] bytes = new byte[length];
			in.get(bytes);//读取类容
			//开始解码
			Context<?> context = new AMF3Context();
			context.decode(bytes);
			out.write(context);
			state.isnew = true;
//			session.setAttribute(Contant.MSG_RECIEVE_COUNT, sendCount);
			return true;

		} 
			
        return false;
		
	}

	private State getState(IoSession session) {
		State state = (State) session.getAttribute(STATE);
		if (null == state) {
			state = new State();
			session.setAttribute(STATE, state);

		}
		return state;
	}
	private Long getRecieveCount(IoSession session) {
		Long count = null;// session.getAttribute(Contant.MSG_RECIEVE_COUNT);
		if (null == count) {
			count = 0l;
		}
		return count;
	}

	public void decode(IoSession session, IoBuffer in,
            ProtocolDecoderOutput out) throws Exception {
        boolean usingSessionBuffer = true;
        in.order(ByteOrder.BIG_ENDIAN);
        //if(in.remaining()>4)
          //log.debug("最原始的长度:"+in.getInt(in.position())+"剩余数据"+in.remaining());
        IoBuffer buf = (IoBuffer) session.getAttribute(BUFFER);
        // If we have a session buffer, append data to that; otherwise
        // use the buffer read from the network directly.
        if (buf != null) {
            boolean appended = false;
            // Make sure that the buffer is auto-expanded.
            if (buf.isAutoExpand()) {
                try {
                    buf.put(in);
                    appended = true;
                } catch (IllegalStateException e) {
                    // A user called derivation method (e.g. slice()),
                    // which disables auto-expansion of the parent buffer.
                } catch (IndexOutOfBoundsException e) {
                    // A user disabled auto-expansion.
                }
            }

            if (appended) {
                buf.flip();
            } else {
                // Reallocate the buffer if append operation failed due to
                // derivation or disabled auto-expansion.
                buf.flip();
                IoBuffer newBuf = IoBuffer.allocate(
                        buf.remaining() + in.remaining()).setAutoExpand(true);
                newBuf.order(buf.order());
                newBuf.put(buf);
                newBuf.put(in);
                newBuf.flip();
                buf = newBuf;

                // Update the session attribute.
                session.setAttribute(BUFFER, buf);
            }
        } else {
            buf = in;
            usingSessionBuffer = false;
        }

        for (;;) {
            int oldPos = buf.position();
            buf.order(ByteOrder.BIG_ENDIAN);
            //if(buf.remaining()>4)
              //log.debug("可能是长度:"+buf.getInt(oldPos)+"; old pos is "+oldPos);
            boolean decoded = doDecode(session, buf, out);
            if (decoded) {
                if (buf.position() == oldPos) {
                    throw new IllegalStateException(
                            "doDecode() can't return true when buffer is not consumed.");
                }

                if (!buf.hasRemaining()) {
                    break;
                }
            } else {
                break;
            }
        }
        //log.debug("是否数据剩余"+buf.hasRemaining()+";是否使用session buffer:"+usingSessionBuffer);
        // if there is any data left that cannot be decoded, we store
        // it in a buffer in the session and next time this decoder is
        // invoked the session buffer gets appended to
        if (buf.hasRemaining()) {
        	
            if (usingSessionBuffer && buf.isAutoExpand()) {
                buf.compact();
            } else {
                storeRemainingInSession(buf, session);
            }
        } else {
            if (usingSessionBuffer) {
                removeSessionBuffer(session);
            }
        }
    }
	@Override
    public void dispose(IoSession session) throws Exception {
        removeSessionBuffer(session);
    }

    private void removeSessionBuffer(IoSession session) {
        session.removeAttribute(BUFFER);
    }

    private void storeRemainingInSession(IoBuffer buf, IoSession session) {
        final IoBuffer remainingBuf = IoBuffer.allocate(buf.capacity()).setAutoExpand(true);

        remainingBuf.order(buf.order());
        remainingBuf.put(buf);

        session.setAttribute(BUFFER, remainingBuf);
    }
}
